#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
WebVNC Tornado SSL 版本
基于参考项目，使用本地Tornado，只保留SSL加密连接功能
"""

# ====== VENDOR LOADER ======
import sys
import os
_vendor_path = os.path.join(os.path.dirname(__file__), 'vendor', 'tornado-6.3.3')
if os.path.isdir(_vendor_path):
    sys.path.insert(0, _vendor_path)
# ==========================

# 标准库
import time
import datetime
import ssl
import logging
import json
import uuid
from collections import defaultdict

# 第三方库（现在来自 vendor）
import tornado.ioloop
import tornado.web
import tornado.websocket
import tornado.httpserver
from tornado import gen
from tornado.tcpclient import TCPClient
from tornado.iostream import StreamClosedError

# 本地模块
from auth_new import auth_manager

# ================== 配置 ==================
VNC_HOST = "127.0.0.1"
VNC_PORT = 5900
BASE_DIR = os.path.dirname(os.path.abspath(__file__))
NOVNC_DIR = os.path.join(BASE_DIR, "novnc")
CERT_DIR = os.path.join(BASE_DIR, "certs")
CERT_FILE = os.path.join(CERT_DIR, "cert.pem")
KEY_FILE = os.path.join(CERT_DIR, "key.pem")

# 会话管理
SESSION_TIMEOUT = 30 * 60
CHECK_INTERVAL = 60
active_sessions = defaultdict(list)
kicked_sessions = set()  # 存储被踢出的会话ID

# 聊天室管理
chat_messages = []  # 存储聊天消息
chat_connections = set()  # 存储聊天WebSocket连接
MAX_CHAT_MESSAGES = 100  # 最大消息数量

# 日志配置
logging.basicConfig(
    level=logging.INFO,
    format='%(asctime)s - %(levelname)s - %(message)s'
)
logger = logging.getLogger(__name__)

# ================== 认证装饰器 ==================
def authenticated(method):
    """认证装饰器"""
    def wrapper(self, *args, **kwargs):
        session_id = self.get_secure_cookie("webvnc_session")
        if not session_id:
            if self.request.headers.get("X-Requested-With") == "XMLHttpRequest":
                self.set_status(401)
                self.write({"success": False, "message": "需要登录"})
                return
            else:
                # 非AJAX请求，返回登录页面
                self.render_login_page()
                return
        
        user = auth_manager.get_user_by_session(session_id.decode())
        if not user:
            self.clear_cookie("webvnc_session")
            if self.request.headers.get("X-Requested-With") == "XMLHttpRequest":
                self.set_status(401)
                self.write({"success": False, "message": "会话已过期"})
                return
            else:
                self.render_login_page()
                return
        
        self.current_user = user
        return method(self, *args, **kwargs)
    return wrapper

# ================== 主页处理器 ==================
class MainHandler(tornado.web.RequestHandler):
    def get(self):
        # 检查系统初始化状态
        if not auth_manager.is_initialized():
            # 数据库不符合要求，重置并要求初始化
            logger.info("🔧 数据库初始化状态不符合要求，执行重置")
            auth_manager.reset_database()
            
            # 只允许127.0.0.1访问初始化页面
            if self.request.remote_ip in ['127.0.0.1', '::1']:
                self.redirect("/initialization.html")
            else:
                self.write("<h1>系统未初始化</h1><p>请联系管理员在本地完成系统初始化</p>")
            return
        
        # 系统已初始化，响应所有IP请求
        # 检查是否已登录
        session_id = self.get_secure_cookie("webvnc_session")
        if session_id:
            user = auth_manager.get_user_by_session(session_id.decode())
            if user:
                # 已登录，跳转到VNC页面
                self.redirect("/vnc.html?autoconnect=1")
                return
        
        # 未登录，显示登录页面
        self.render_login_page()
    
    def render_login_page(self):
        """渲染登录页面"""
        try:
            with open(os.path.join(BASE_DIR, "templates", "login_modal.html"), "r", encoding="utf-8") as f:
                login_html = f.read()
            self.write(login_html)
        except FileNotFoundError:
            self.write("<h1>登录页面未找到</h1><p>请确保 login_modal.html 文件存在</p>")

# ================== API处理器 ==================
class LoginAPIHandler(tornado.web.RequestHandler):
    """登录API处理器"""
    
    def post(self):
        try:
            data = json.loads(self.request.body.decode())
            username = data.get('username', '').strip()
            password = data.get('password', '')
            
            if not username or not password:
                self.write({"success": False, "message": "用户名和密码不能为空"})
                return
            
            # 验证用户
            user = auth_manager.verify_user(username, password, self.request.remote_ip)
            if not user:
                self.write({"success": False, "message": "用户名或密码错误"})
                return
            
            # 创建会话（会自动踢出旧的会话）
            session_id = auth_manager.create_session(user)
            
            # 设置安全Cookie
            self.set_secure_cookie("webvnc_session", session_id, 
                                 expires_days=1, httponly=True)
            
            logger.info(f"✅ 用户登录成功: {username} ({self.request.remote_ip})")
            
            # 检查是否踢出了旧的会话
            kicked_count = len([s for s in auth_manager.kicked_sessions if s != session_id])
            if kicked_count > 0:
                logger.info(f"🔄 用户 {username} 重新登录，踢出了 {kicked_count} 个旧会话")
            
            self.write({
                "success": True,
                "message": "登录成功",
                "user": {
                    "user_id": user.user_id,
                    "username": user.username,
                    "permission_level": user.permission_level
                }
            })
            
        except json.JSONDecodeError:
            self.write({"success": False, "message": "请求数据格式错误"})
        except Exception as e:
            logger.error(f"登录处理错误: {e}")
            self.write({"success": False, "message": "服务器内部错误"})

class LogoutAPIHandler(tornado.web.RequestHandler):
    """登出API处理器"""
    
    def post(self):
        session_id = self.get_secure_cookie("webvnc_session")
        if session_id:
            auth_manager.remove_session(session_id.decode())
            self.clear_cookie("webvnc_session")
            logger.info(f"✅ 用户登出: {self.request.remote_ip}")
        
        self.write({"success": True, "message": "登出成功"})

class StatusAPIHandler(tornado.web.RequestHandler):
    """状态API处理器"""
    
    @authenticated
    def get(self):
        user = self.current_user
        active_users = auth_manager.get_all_active_users()
        
        self.write({
            "success": True,
            "current_user": {
                "user_id": user.user_id,
                "username": user.username,
                "permission_level": user.permission_level,
                "login_time": user.login_time.isoformat() if user.login_time else None,
                "last_active": user.last_active.isoformat() if user.last_active else None
            },
            "active_users": len(active_users),
            "vnc_target": f"{VNC_HOST}:{VNC_PORT}"
        })

class CurrentUserAPIHandler(tornado.web.RequestHandler):
    """当前用户API处理器"""
    
    @authenticated
    def get(self):
        user = self.current_user
        
        logger.info(f"📋 获取当前用户信息: {user.username} (权限级别: {user.permission_level})")
        
        permissions = auth_manager.get_user_permissions(user)
        logger.info(f"🔐 用户权限: {permissions}")
        
        self.write({
            "success": True,
            "user": {
                "user_id": user.user_id,
                "username": user.username,
                "permission_level": user.permission_level,
                "permission_name": auth_manager.get_permission_name(user.permission_level),
                "permissions": permissions
            }
        })

class ActiveUsersAPIHandler(tornado.web.RequestHandler):
    """活跃用户API处理器"""
    
    @authenticated
    def get(self):
        # 只有管理员可以查看所有用户
        if self.current_user.permission_level < auth_manager.PERMISSION_ADMIN:
            self.set_status(403)
            self.write({"success": False, "message": "权限不足"})
            return
        
        active_users = auth_manager.get_all_active_users()
        users_list = []
        
        for user_id, user in active_users.items():
            users_list.append({
                "user_id": user.user_id,
                "username": user.username,
                "permission_level": user.permission_level,
                "permission_name": auth_manager.get_permission_name(user.permission_level),
                "login_time": user.login_time.isoformat() if user.login_time else None,
                "last_active": user.last_active.isoformat() if user.last_active else None
            })
        
        self.write({
            "success": True,
            "users": users_list
        })

class KickUserAPIHandler(tornado.web.RequestHandler):
    """踢出用户API处理器"""
    
    @authenticated
    def post(self):
        # 只有管理员可以踢出用户
        if self.current_user.permission_level < auth_manager.PERMISSION_ADMIN:
            self.set_status(403)
            self.write({"success": False, "message": "权限不足"})
            return
        
        try:
            data = json.loads(self.request.body.decode())
            target_user_id = data.get('user_id')
            
            if not target_user_id:
                self.write({"success": False, "message": "用户ID不能为空"})
                return
            
            # 不能踢出自己
            if target_user_id == self.current_user.user_id:
                self.write({"success": False, "message": "不能踢出自己"})
                return
            
            # 查找目标用户
            target_user = None
            kicked_session_id = None
            for session_id, user_id in auth_manager.sessions.items():
                if user_id == target_user_id:
                    target_user = auth_manager.users.get(user_id)
                    if target_user:
                        kicked_session_id = session_id
                        # 移除会话
                        auth_manager.remove_session(session_id)
                        # 添加到被踢出集合
                        kicked_sessions.add(session_id)
                        # 添加到auth_manager的被踢出集合
                        auth_manager.kicked_sessions.add(session_id)
                        logger.info(f"👢 用户 {target_user.username} 被管理员 {self.current_user.username} 踢出")
                        
                        # 通知被踢出的用户
                        self.notify_kicked_user(session_id, target_user.username)
                        break
            
            if target_user:
                self.write({"success": True, "message": f"用户 {target_user.username} 已被踢出"})
            else:
                self.write({"success": False, "message": "用户不存在或已下线"})
                
        except json.JSONDecodeError:
            self.write({"success": False, "message": "请求数据格式错误"})
        except Exception as e:
            logger.error(f"踢出用户错误: {e}")
            self.write({"success": False, "message": "服务器内部错误"})
    
    def notify_kicked_user(self, session_id, username):
        """通知被踢出的用户"""
        try:
            # 通过WebSocket发送踢出通知
            for connection in chat_connections:
                if hasattr(connection, 'current_user') and connection.current_user.username == username:
                    connection.write_message(json.dumps({
                        "type": "system",
                        "content": f"您已被管理员踢出，连接将在3秒后断开"
                    }))
                    break
            
            # 记录日志
            logger.info(f"📢 已向用户 {username} 发送踢出通知")
            
        except Exception as e:
            logger.error(f"发送踢出通知失败: {e}")

class CheckKickStatusHandler(tornado.web.RequestHandler):
    """检查踢出状态API处理器"""
    
    def get(self):
        session_id = self.get_secure_cookie("webvnc_session")
        if not session_id:
            self.write({"kicked": False, "message": "未登录"})
            return
        
        session_id_str = session_id.decode()
        
        # 检查是否被踢出（使用auth_manager的kicked_sessions）
        if auth_manager.is_session_kicked(session_id_str):
            # 从被踢出集合中移除（避免重复检查）
            auth_manager.clear_kicked_session(session_id_str)
            # 清除Cookie
            self.clear_cookie("webvnc_session")
            self.write({"kicked": True, "message": "您已被踢出（可能是由于在别处登录）"})
        else:
            self.write({"kicked": False, "message": "正常"})

# ================== 初始化和用户管理API处理器 ==================
class CheckInitHandler(tornado.web.RequestHandler):
    """检查初始化状态API处理器"""
    
    def get(self):
        # 只允许127.0.0.1访问
        if self.request.remote_ip not in ['127.0.0.1', '::1']:
            self.set_status(403)
            self.write({"success": False, "message": "仅允许本地访问"})
            return
        
        initialized = auth_manager.is_initialized()
        self.write({
            "success": True,
            "initialized": initialized
        })

class InitializeHandler(tornado.web.RequestHandler):
    """系统初始化API处理器"""
    
    def post(self):
        # 只允许127.0.0.1访问
        if self.request.remote_ip not in ['127.0.0.1', '::1']:
            self.set_status(403)
            self.write({"success": False, "message": "仅允许本地访问"})
            return
        
        try:
            data = json.loads(self.request.body.decode())
            username = data.get('username', '').strip()
            password = data.get('password', '')
            
            if not username or not password:
                self.write({"success": False, "message": "用户名和密码不能为空"})
                return
            
            # 检查是否已初始化
            if auth_manager.is_initialized():
                self.write({"success": False, "message": "系统已初始化"})
                return
            
            # 验证系统用户（直接使用系统认证，不依赖数据库中的用户记录）
            try:
                from auth_os import authenticate
                if not authenticate(username, password):
                    self.write({"success": False, "message": "系统用户认证失败"})
                    return
            except ImportError:
                self.write({"success": False, "message": "系统认证模块不可用"})
                return
            except Exception as e:
                self.write({"success": False, "message": f"系统认证错误: {e}"})
                return
            
            # 创建管理员用户
            if auth_manager.create_admin(username):
                self.write({
                    "success": True,
                    "message": f"系统初始化成功，管理员用户: {username}"
                })
            else:
                self.write({"success": False, "message": "创建管理员用户失败"})
                
        except json.JSONDecodeError:
            self.write({"success": False, "message": "请求数据格式错误"})
        except Exception as e:
            logger.error(f"系统初始化错误: {e}")
            self.write({"success": False, "message": "服务器内部错误"})

class UsersAPIHandler(tornado.web.RequestHandler):
    """用户管理API处理器"""
    
    @authenticated
    def get(self):
        # 只有管理员可以查看用户列表
        if self.current_user.permission_level < auth_manager.PERMISSION_ADMIN:
            self.set_status(403)
            self.write({"success": False, "message": "权限不足"})
            return
        
        users = auth_manager.get_all_users()
        users_list = []
        
        for user in users:
            users_list.append({
                "user_id": user.user_id,
                "username": user.username,
                "permission_level": user.permission_level,
                "permission_name": auth_manager.get_permission_name(user.permission_level),
                "created_time": user.created_time if hasattr(user, 'created_time') else None
            })
        
        self.write({
            "success": True,
            "users": users_list
        })

class AddUserAPIHandler(tornado.web.RequestHandler):
    """添加用户API处理器"""
    
    @authenticated
    def post(self):
        # 只有管理员可以添加用户
        if self.current_user.permission_level < auth_manager.PERMISSION_ADMIN:
            self.set_status(403)
            self.write({"success": False, "message": "权限不足"})
            return
        
        try:
            data = json.loads(self.request.body.decode())
            username = data.get('username', '').strip()
            password = data.get('password', '')
            permission_level = data.get('permission_level', 2)
            
            if not username or not password:
                self.write({"success": False, "message": "用户名和密码不能为空"})
                return
            
            success, message = auth_manager.add_user(
                username, password, permission_level, self.current_user.username
            )
            
            self.write({
                "success": success,
                "message": message
            })
            
        except json.JSONDecodeError:
            self.write({"success": False, "message": "请求数据格式错误"})
        except Exception as e:
            logger.error(f"添加用户错误: {e}")
            self.write({"success": False, "message": "服务器内部错误"})

class DeleteUserAPIHandler(tornado.web.RequestHandler):
    """删除用户API处理器"""
    
    @authenticated
    def post(self):
        # 只有管理员可以删除用户
        if self.current_user.permission_level < auth_manager.PERMISSION_ADMIN:
            self.set_status(403)
            self.write({"success": False, "message": "权限不足"})
            return
        
        try:
            data = json.loads(self.request.body.decode())
            username = data.get('username', '').strip()
            
            if not username:
                self.write({"success": False, "message": "用户名不能为空"})
                return
            
            success, message = auth_manager.delete_user(username, self.current_user.username)
            
            self.write({
                "success": success,
                "message": message
            })
            
        except json.JSONDecodeError:
            self.write({"success": False, "message": "请求数据格式错误"})
        except Exception as e:
            logger.error(f"删除用户错误: {e}")
            self.write({"success": False, "message": "服务器内部错误"})

class LogsAPIHandler(tornado.web.RequestHandler):
    """日志查看API处理器"""
    
    @authenticated
    def get(self):
        # 只有管理员可以查看日志
        if self.current_user.permission_level < auth_manager.PERMISSION_ADMIN:
            self.set_status(403)
            self.write({"success": False, "message": "权限不足"})
            return
        
        try:
            limit = min(int(self.get_argument("limit", 50)), 100)
            logs = auth_manager.get_recent_logs(limit)
            
            self.write({
                "success": True,
                "logs": logs
            })
            
        except ValueError:
            self.write({"success": False, "message": "参数错误"})
        except Exception as e:
            logger.error(f"获取日志错误: {e}")
            self.write({"success": False, "message": "服务器内部错误"})

class LogsExportHandler(tornado.web.RequestHandler):
    """日志导出API处理器"""
    
    def render_login_page(self):
        """渲染登录页面"""
        try:
            with open(os.path.join(BASE_DIR, "templates", "login_modal.html"), "r", encoding="utf-8") as f:
                login_html = f.read()
            self.write(login_html)
        except FileNotFoundError:
            self.write("<h1>登录页面未找到</h1><p>请确保 login_modal.html 文件存在</p>")
    
    @authenticated
    def get(self):
        # 只有管理员可以导出日志
        if self.current_user.permission_level < auth_manager.PERMISSION_ADMIN:
            self.set_status(403)
            self.write({"success": False, "message": "权限不足"})
            return
        
        try:
            # 获取日志数量限制
            limit = min(int(self.get_argument("limit", 1000)), 5000)
            logs = auth_manager.get_recent_logs(limit)
            
            if not logs:
                self.set_status(404)
                self.write({"success": False, "message": "没有日志数据"})
                return
            
            # 生成CSV内容
            csv_content = self._generate_csv(logs)
            
            # 设置响应头
            filename = f"webvnc_logs_{datetime.datetime.now().strftime('%Y-%m-%d_%H-%M-%S')}.csv"
            self.set_header('Content-Type', 'text/csv; charset=utf-8')
            self.set_header('Content-Disposition', f'attachment; filename="{filename}"')
            
            # 写入CSV内容
            self.write(csv_content)
            
            # 记录导出日志
            logger.info(f"📥 管理员 {self.current_user.username} 导出了 {len(logs)} 条日志")
            
        except ValueError:
            self.set_status(400)
            self.write({"success": False, "message": "参数错误"})
        except Exception as e:
            logger.error(f"导出日志错误: {e}")
            self.set_status(500)
            self.write({"success": False, "message": "服务器内部错误"})
    
    def _generate_csv(self, logs):
        """生成CSV内容"""
        import io
        
        # 使用StringIO来构建CSV内容
        output = io.StringIO()
        
        # 写入BOM以支持Excel正确显示中文
        output.write('\ufeff')
        
        # 写入CSV头部
        output.write('Timestamp,Content\n')
        
        # 写入日志数据
        for log in logs:
            if isinstance(log, (list, tuple)) and len(log) >= 2:
                timestamp = str(log[0] if log[0] else '')
                content = str(log[1] if log[1] else '')
            elif isinstance(log, dict):
                timestamp = str(log.get('timestamp', ''))
                content = str(log.get('content', ''))
            else:
                continue
            
            # CSV转义：如果包含逗号、引号或换行符，需要用引号包裹并转义内部引号
            if ',' in content or '"' in content or '\n' in content or '\r' in content:
                content = '"' + content.replace('"', '""') + '"'
            
            # 时间戳也需要转义
            if ',' in timestamp or '"' in timestamp or '\n' in timestamp or '\r' in timestamp:
                timestamp = '"' + timestamp.replace('"', '""') + '"'
            
            output.write(f'{timestamp},{content}\n')
        
        # 获取CSV内容
        csv_content = output.getvalue()
        output.close()
        
        return csv_content

class InitializationPageHandler(tornado.web.RequestHandler):
    """系统初始化页面处理器"""
    
    def get(self):
        # 只允许本地访问初始化页面
        if self.request.remote_ip not in ['127.0.0.1', '::1']:
            self.set_status(403)
            self.write("<h1>访问被拒绝</h1><p>初始化页面仅允许本地访问</p>")
            return
        
        try:
            with open(os.path.join(BASE_DIR, "templates", "initialization.html"), "r", encoding="utf-8") as f:
                content = f.read()
            self.write(content)
        except FileNotFoundError:
            self.write("<h1>初始化页面未找到</h1>")

class UserManagementHandler(tornado.web.RequestHandler):
    """用户管理页面处理器"""
    
    def render_login_page(self):
        """渲染登录页面"""
        try:
            with open(os.path.join(BASE_DIR, "templates", "login_modal.html"), "r", encoding="utf-8") as f:
                login_html = f.read()
            self.write(login_html)
        except FileNotFoundError:
            self.write("<h1>登录页面未找到</h1><p>请确保 login_modal.html 文件存在</p>")
    
    @authenticated
    def get(self):
        # 只有管理员可以访问用户管理页面
        if self.current_user.permission_level < auth_manager.PERMISSION_ADMIN:
            self.redirect("/vnc.html")
            return
        
        try:
            with open(os.path.join(BASE_DIR, "templates", "user_management.html"), "r", encoding="utf-8") as f:
                content = f.read()
            self.write(content)
        except FileNotFoundError:
            self.write("<h1>用户管理页面未找到</h1>")

# ================== 文件管理API处理器 ==================
class FileListAPIHandler(tornado.web.RequestHandler):
    """文件列表API处理器"""
    
    @authenticated
    def post(self):
        try:
            data = json.loads(self.request.body.decode())
            
            # 获取管理员用户来确定共享目录路径
            admin_user = auth_manager.get_admin_user()
            if not admin_user:
                self.write({"success": False, "message": "系统未初始化或管理员不存在"})
                return
            
            # 动态构建共享目录路径
            shared_path = f"/home/{admin_user.username}/Desktop/webvnc_file"
            
            # 检查路径是否有效
            if not self._validate_file_path(shared_path):
                self.write({"success": False, "message": f"文件路径无效或不可访问: {shared_path}"})
                return
            
            # 确保目录存在
            try:
                os.makedirs(shared_path, exist_ok=True)
            except Exception as e:
                logger.error(f"创建文件目录失败: {e}")
                self.write({"success": False, "message": f"无法创建文件目录: {shared_path}"})
                return
            
            # 获取文件列表
            files = []
            try:
                for item in os.listdir(shared_path):
                    item_path = os.path.join(shared_path, item)
                    if os.path.isfile(item_path):
                        size = os.path.getsize(item_path)
                        files.append({
                            "name": item,
                            "size": size
                        })
            except Exception as e:
                logger.error(f"读取文件列表失败: {e}")
                self.write({"success": False, "message": "读取文件列表失败"})
                return
            
            self.write({
                "success": True,
                "files": files,
                "path": shared_path
            })
            
        except json.JSONDecodeError:
            self.write({"success": False, "message": "请求数据格式错误"})
        except Exception as e:
            logger.error(f"获取文件列表错误: {e}")
            self.write({"success": False, "message": "服务器内部错误"})
    
    def _validate_file_path(self, path):
        """验证文件路径是否有效且可访问"""
        try:
            # 检查路径是否存在
            if not os.path.exists(path):
                # 尝试创建目录
                try:
                    os.makedirs(path, exist_ok=True)
                    logger.info(f"📁 创建文件目录: {path}")
                except Exception as e:
                    logger.error(f"无法创建文件目录 {path}: {e}")
                    return False
            
            # 检查是否可读写
            if not os.access(path, os.R_OK | os.W_OK):
                logger.error(f"文件目录权限不足: {path}")
                return False
            
            # 检查是否为目录
            if not os.path.isdir(path):
                logger.error(f"路径不是目录: {path}")
                return False
            
            return True
            
        except Exception as e:
            logger.error(f"验证文件路径失败 {path}: {e}")
            return False

class FileUploadAPIHandler(tornado.web.RequestHandler):
    """文件上传API处理器"""
    
    @authenticated
    def post(self):
        try:
            # 获取管理员用户来确定共享目录路径
            admin_user = auth_manager.get_admin_user()
            if not admin_user:
                self.write({"success": False, "message": "系统未初始化或管理员不存在"})
                return
            
            # 动态构建共享目录路径
            shared_path = f"/home/{admin_user.username}/Desktop/webvnc_file"
            
            # 检查路径是否有效
            if not self._validate_file_path(shared_path):
                self.write({"success": False, "message": f"文件路径无效或不可访问: {shared_path}"})
                return
            
            # 检查是否有文件上传
            if not self.request.files or 'file' not in self.request.files:
                self.write({"success": False, "message": "没有上传文件"})
                return
            
            # 获取上传的文件
            file_info = self.request.files['file'][0]
            filename = file_info['filename']
            file_body = file_info['body']
            
            if not filename:
                self.write({"success": False, "message": "文件名不能为空"})
                return
            
            # 保存文件
            file_path = os.path.join(shared_path, filename)
            
            # 避免文件名冲突
            counter = 1
            original_path = file_path
            while os.path.exists(file_path):
                name, ext = os.path.splitext(original_path)
                file_path = f"{name}_{counter}{ext}"
                counter += 1
            
            # 保存文件并设置权限
            with open(file_path, 'wb') as f:
                f.write(file_body)
            
            # 设置文件权限为所有人都可以读写
            os.chmod(file_path, 0o666)
            
            self.write({
                "success": True,
                "message": f"文件上传成功: {os.path.basename(file_path)}",
                "filename": os.path.basename(file_path)
            })
            
        except Exception as e:
            logger.error(f"文件上传错误: {e}")
            self.write({"success": False, "message": "文件上传失败"})
    
    def _validate_file_path(self, path):
        """验证文件路径是否有效且可访问"""
        try:
            # 检查路径是否存在
            if not os.path.exists(path):
                # 尝试创建目录
                try:
                    os.makedirs(path, exist_ok=True)
                    logger.info(f"📁 创建文件目录: {path}")
                except Exception as e:
                    logger.error(f"无法创建文件目录 {path}: {e}")
                    return False
            
            # 检查是否可读写
            if not os.access(path, os.R_OK | os.W_OK):
                logger.error(f"文件目录权限不足: {path}")
                return False
            
            # 检查是否为目录
            if not os.path.isdir(path):
                logger.error(f"路径不是目录: {path}")
                return False
            
            return True
            
        except Exception as e:
            logger.error(f"验证文件路径失败 {path}: {e}")
            return False

class FileDownloadAPIHandler(tornado.web.RequestHandler):
    """文件下载API处理器"""
    
    @authenticated
    def get(self):
        try:
            filename = self.get_argument('filename', '')
            
            if not filename:
                self.set_status(400)
                self.write({"success": False, "message": "文件名不能为空"})
                return
            
            # 获取管理员用户来确定共享目录路径
            admin_user = auth_manager.get_admin_user()
            if not admin_user:
                self.set_status(500)
                self.write({"success": False, "message": "系统未初始化或管理员不存在"})
                return
            
            # 所有用户共享同一个文件目录
            shared_path = f"/home/{admin_user.username}/Desktop/webvnc_file"
            
            # 构建完整的文件路径
            file_path = os.path.join(shared_path, filename)
            
            # 检查文件是否存在
            if not os.path.exists(file_path) or not os.path.isfile(file_path):
                self.set_status(404)
                self.write({"success": False, "message": "文件不存在"})
                return
            
            # 设置响应头
            self.set_header('Content-Type', 'application/octet-stream')
            self.set_header('Content-Disposition', f'attachment; filename="{filename}"')
            
            # 读取并发送文件
            with open(file_path, 'rb') as f:
                while True:
                    chunk = f.read(8192)
                    if not chunk:
                        break
                    self.write(chunk)
                    self.flush()
            
        except Exception as e:
            logger.error(f"文件下载错误: {e}")
            self.set_status(500)
            self.write({"success": False, "message": "文件下载失败"})

class FileDeleteAPIHandler(tornado.web.RequestHandler):
    """文件删除API处理器"""
    
    @authenticated
    def post(self):
        try:
            data = json.loads(self.request.body.decode())
            filename = data.get('filename', '')
            
            if not filename:
                self.write({"success": False, "message": "文件名不能为空"})
                return
            
            # 获取管理员用户来确定共享目录路径
            admin_user = auth_manager.get_admin_user()
            if not admin_user:
                self.write({"success": False, "message": "系统未初始化或管理员不存在"})
                return
            
            # 所有用户共享同一个文件目录
            shared_path = f"/home/{admin_user.username}/Desktop/webvnc_file"
            
            # 构建完整的文件路径
            file_path = os.path.join(shared_path, filename)
            
            # 检查文件是否存在
            if not os.path.exists(file_path) or not os.path.isfile(file_path):
                self.write({"success": False, "message": "文件不存在"})
                return
            
            # 删除文件
            os.remove(file_path)
            
            self.write({
                "success": True,
                "message": f"文件 '{filename}' 删除成功"
            })
            
        except json.JSONDecodeError:
            self.write({"success": False, "message": "请求数据格式错误"})
        except Exception as e:
            logger.error(f"删除文件错误: {e}")
            self.write({"success": False, "message": "删除文件失败"})

class FileRenameAPIHandler(tornado.web.RequestHandler):
    """文件重命名API处理器"""
    
    @authenticated
    def post(self):
        try:
            data = json.loads(self.request.body.decode())
            old_filename = data.get('old_filename', '')
            new_filename = data.get('new_filename', '').strip()
            
            if not old_filename or not new_filename:
                self.write({"success": False, "message": "文件名不能为空"})
                return
            
            # 验证新文件名
            if any(char in new_filename for char in r'<>:"/\|?*'):
                self.write({"success": False, "message": "文件名包含非法字符"})
                return
            
            # 获取管理员用户来确定共享目录路径
            admin_user = auth_manager.get_admin_user()
            if not admin_user:
                self.write({"success": False, "message": "系统未初始化或管理员不存在"})
                return
            
            # 所有用户共享同一个文件目录
            shared_path = f"/home/{admin_user.username}/Desktop/webvnc_file"
            
            # 构建完整的文件路径
            old_file_path = os.path.join(shared_path, old_filename)
            new_file_path = os.path.join(shared_path, new_filename)
            
            # 检查原文件是否存在
            if not os.path.exists(old_file_path) or not os.path.isfile(old_file_path):
                self.write({"success": False, "message": "原文件不存在"})
                return
            
            # 检查新文件名是否已存在
            if os.path.exists(new_file_path):
                self.write({"success": False, "message": "目标文件名已存在"})
                return
            
            # 重命名文件
            os.rename(old_file_path, new_file_path)
            
            self.write({
                "success": True,
                "message": f"文件重命名成功: '{old_filename}' → '{new_filename}'"
            })
            
        except json.JSONDecodeError:
            self.write({"success": False, "message": "请求数据格式错误"})
        except Exception as e:
            logger.error(f"重命名文件错误: {e}")
            self.write({"success": False, "message": "重命名文件失败"})

# ================== 聊天室API处理器 ==================
class ChatSendAPIHandler(tornado.web.RequestHandler):
    """聊天消息发送API处理器"""
    
    @authenticated
    def post(self):
        try:
            data = json.loads(self.request.body.decode())
            content = data.get('content', '').strip()
            
            if not content:
                self.write({"success": False, "message": "消息内容不能为空"})
                return
            
            if len(content) > 500:
                self.write({"success": False, "message": "消息内容过长，最多500字符"})
                return
            
            user = self.current_user
            
            # 创建消息
            message = {
                "id": len(chat_messages) + 1,
                "username": user.username,
                "user_id": user.user_id,
                "permission_level": user.permission_level,
                "content": content,
                "timestamp": int(time.time())
            }
            
            # 添加到消息列表
            chat_messages.append(message)
            
            # 限制消息数量
            if len(chat_messages) > MAX_CHAT_MESSAGES:
                chat_messages.pop(0)
            
            # 广播消息给所有连接的客户端
            broadcast_chat_message({
                "type": "message",
                **message
            })
            
            logger.info(f"💬 聊天消息: {user.username}: {content}")
            
            self.write({"success": True, "message": "消息发送成功"})
            
        except json.JSONDecodeError:
            self.write({"success": False, "message": "请求数据格式错误"})
        except Exception as e:
            logger.error(f"发送聊天消息错误: {e}")
            self.write({"success": False, "message": "服务器内部错误"})

class ChatMessagesAPIHandler(tornado.web.RequestHandler):
    """聊天消息获取API处理器"""
    
    @authenticated
    def get(self):
        try:
            since_id = int(self.get_argument("since", 0))
            
            # 获取指定ID之后的消息
            messages = [msg for msg in chat_messages if msg["id"] > since_id]
            
            self.write({
                "success": True,
                "messages": messages
            })
            
        except ValueError:
            self.write({"success": False, "message": "参数错误"})
        except Exception as e:
            logger.error(f"获取聊天消息错误: {e}")
            self.write({"success": False, "message": "服务器内部错误"})

class ChatRecentAPIHandler(tornado.web.RequestHandler):
    """最近聊天消息API处理器"""
    
    @authenticated
    def get(self):
        try:
            limit = min(int(self.get_argument("limit", 20)), 50)
            
            # 获取最近的N条消息
            recent_messages = chat_messages[-limit:] if chat_messages else []
            
            self.write({
                "success": True,
                "messages": recent_messages
            })
            
        except ValueError:
            self.write({"success": False, "message": "参数错误"})
        except Exception as e:
            logger.error(f"获取最近聊天消息错误: {e}")
            self.write({"success": False, "message": "服务器内部错误"})

class ChatOnlineUsersAPIHandler(tornado.web.RequestHandler):
    """在线用户API处理器"""
    
    @authenticated
    def get(self):
        try:
            active_users = auth_manager.get_all_active_users()
            users_list = []
            
            for user_id, user in active_users.items():
                users_list.append({
                    "user_id": user.user_id,
                    "username": user.username,
                    "permission_level": user.permission_level
                })
            
            self.write({
                "success": True,
                "users": users_list
            })
            
        except Exception as e:
            logger.error(f"获取在线用户错误: {e}")
            self.write({"success": False, "message": "服务器内部错误"})

class ChatWebSocketHandler(tornado.websocket.WebSocketHandler):
    """聊天室WebSocket处理器"""
    
    def check_origin(self, origin):
        return True
    
    def open(self):
        # 检查认证
        session_id = self.get_secure_cookie("webvnc_session")
        if not session_id:
            logger.warning(f"❌ 聊天WebSocket连接未认证: {self.request.remote_ip}")
            self.close(code=4001, reason="未认证")
            return
        
        user = auth_manager.get_user_by_session(session_id.decode())
        if not user:
            logger.warning(f"❌ 聊天WebSocket会话过期: {self.request.remote_ip}")
            self.close(code=4001, reason="会话过期")
            return
        
        self.current_user = user
        self.connection_id = str(uuid.uuid4())
        
        # 添加到连接集合
        chat_connections.add(self)
        
        logger.info(f"💬 聊天室连接: {user.username} ({self.connection_id})")
        
        # 发送欢迎消息
        self.write_message(json.dumps({
            "type": "system",
            "content": f"欢迎 {user.username} 加入聊天室"
        }))
        
        # 发送最近的消息
        recent_messages = chat_messages[-20:] if chat_messages else []
        for message in recent_messages:
            self.write_message(json.dumps({
                "type": "message",
                **message
            }))
    
    def on_close(self):
        # 从连接集合中移除
        chat_connections.discard(self)
        
        if hasattr(self, 'current_user') and self.current_user:
            logger.info(f"💬 聊天室断开: {self.current_user.username}")
            
            # 广播用户离开消息
            broadcast_chat_message({
                "type": "system",
                "content": f"{self.current_user.username} 离开了聊天室"
            })
        else:
            logger.info(f"💬 聊天室断开: 未认证用户")
    
    def on_message(self, message):
        try:
            data = json.loads(message)
            
            if data.get("type") == "message":
                content = data.get("content", "").strip()
                
                if not content:
                    return
                
                if len(content) > 500:
                    self.write_message(json.dumps({
                        "type": "error",
                        "content": "消息内容过长，最多500字符"
                    }))
                    return
                
                user = self.current_user
                
                # 创建消息
                chat_message = {
                    "id": len(chat_messages) + 1,
                    "username": user.username,
                    "user_id": user.user_id,
                    "permission_level": user.permission_level,
                    "content": content,
                    "timestamp": int(time.time())
                }
                
                # 添加到消息列表
                chat_messages.append(chat_message)
                
                # 限制消息数量
                if len(chat_messages) > MAX_CHAT_MESSAGES:
                    chat_messages.pop(0)
                
                # 广播消息
                broadcast_data = {
                    "type": "message",
                    **chat_message
                }
                broadcast_chat_message(broadcast_data)
                
                logger.info(f"💬 聊天消息 (WebSocket): {user.username}: {content}")
            
            elif data.get("type") == "ping":
                # 心跳响应
                self.write_message(json.dumps({"type": "pong"}))
                
        except json.JSONDecodeError:
            logger.warning(f"聊天室收到无效JSON消息: {message}")
        except Exception as e:
            logger.error(f"聊天室处理消息错误: {e}")

def broadcast_chat_message(data):
    """广播聊天消息给所有连接的客户端"""
    message = json.dumps(data)
    disconnected_clients = set()
    
    for connection in chat_connections:
        try:
            connection.write_message(message)
        except Exception as e:
            logger.warning(f"广播消息失败: {e}")
            disconnected_clients.add(connection)
    
    # 移除断开的连接
    for client in disconnected_clients:
        chat_connections.discard(client)

# ================== VNC WebSocket 代理 ==================
class VncWebSocketProxy(tornado.websocket.WebSocketHandler):
    def check_origin(self, origin):
        return True

    async def open(self):
        # 检查认证
        session_id = self.get_secure_cookie("webvnc_session")
        if not session_id:
            logger.warning(f"❌ WebSocket连接未认证: {self.request.remote_ip}")
            self.close(code=4001, reason="未认证")
            return
        
        user = auth_manager.get_user_by_session(session_id.decode())
        if not user:
            logger.warning(f"❌ WebSocket会话过期: {self.request.remote_ip}")
            self.close(code=4001, reason="会话过期")
            return
        
        self.current_user = user
        self.start_time = time.time()
        self.last_active = time.time()
        
        try:
            logger.info(f"📞 新的WebSocket连接来自: {self.request.remote_ip} (用户: {user.username})")
            
            # 连接到VNC服务器
            self.tcp_client = TCPClient()
            self.vnc_stream = await self.tcp_client.connect(VNC_HOST, VNC_PORT)
            logger.info(f"✅ VNC连接成功: {VNC_HOST}:{VNC_PORT}")
            
            # 开始双向数据传输
            self.read_from_vnc()
            self.start_timeout_checker()
            
        except Exception as e:
            logger.error(f"❌ VNC连接失败: {e}")
            self.close()

    def on_close(self):
        logger.info(f"🔌 WebSocket连接关闭")
        if hasattr(self, 'vnc_stream') and not self.vnc_stream.closed():
            self.vnc_stream.close()

    def start_timeout_checker(self):
        async def _checker():
            while True:
                if self.close_code is not None: 
                    break
                await gen.sleep(CHECK_INTERVAL)
                if time.time() - self.last_active > SESSION_TIMEOUT:
                    logger.info(f"⏰ 连接超时，关闭连接")
                    self.close(code=4001, reason="Timeout")
                    break
        tornado.ioloop.IOLoop.current().spawn_callback(_checker)

    def read_from_vnc(self):
        async def _read():
            try:
                while True:
                    if self.close_code is not None: 
                        break
                    data = await self.vnc_stream.read_bytes(4096, partial=True)
                    if data and self.close_code is None:
                        self.write_message(data, binary=True)
                        logger.debug(f"📤 VNC -> WebSocket: {len(data)} 字节")
            except StreamClosedError:
                logger.info("🔌 VNC连接已关闭")
            except Exception as e:
                logger.error(f"❌ 读取VNC数据错误: {e}")
            finally:
                self.close()
        tornado.ioloop.IOLoop.current().spawn_callback(_read)

    def on_message(self, message):
        self.last_active = time.time()
        if hasattr(self, 'vnc_stream') and not self.vnc_stream.closed():
            if isinstance(message, bytes):
                self.vnc_stream.write(message)
                logger.debug(f"📥 WebSocket -> VNC: {len(message)} 字节")

    def on_ping(self, data):
        self.last_active = time.time()

# ================== VNC 页面处理器（带认证） ==================
class VncPageHandler(tornado.web.RequestHandler):
    def render_login_page(self):
        """渲染登录页面"""
        try:
            with open(os.path.join(BASE_DIR, "templates", "login_modal.html"), "r", encoding="utf-8") as f:
                login_html = f.read()
            self.write(login_html)
        except FileNotFoundError:
            self.write("<h1>登录页面未找到</h1><p>请确保 login_modal.html 文件存在</p>")
    
    @authenticated
    def get(self):
        # 已认证用户，直接提供 VNC 页面
        self.set_header('Content-Type', 'text/html; charset=utf-8')
        try:
            with open(os.path.join(NOVNC_DIR, 'vnc.html'), 'r', encoding='utf-8') as f:
                content = f.read()
            self.write(content)
        except FileNotFoundError:
            self.write("<h1>VNC 页面未找到</h1>")

# ================== 静态文件处理器 ==================
class StaticFileHandler(tornado.web.StaticFileHandler):
    def get_absolute_path(self, root, path):
        # 处理根路径请求
        if path == '':
            path = 'vnc.html'
        return super().get_absolute_path(root, path)

# ================== 启动函数 ==================
def create_app():
    """创建Tornado应用"""
    return tornado.web.Application([
        (r"/", MainHandler),
        (r"/vnc.html", VncPageHandler),
        (r"/api/login", LoginAPIHandler),
        (r"/api/logout", LogoutAPIHandler),
        (r"/api/status", StatusAPIHandler),
        (r"/api/current_user", CurrentUserAPIHandler),
        (r"/api/active_users", ActiveUsersAPIHandler),
        (r"/api/kick_user", KickUserAPIHandler),
        (r"/api/check_kick_status", CheckKickStatusHandler),
        # 初始化和用户管理API端点
        (r"/api/check_init", CheckInitHandler),
        (r"/api/initialize", InitializeHandler),
        (r"/api/users", UsersAPIHandler),
        (r"/api/add_user", AddUserAPIHandler),
        (r"/api/delete_user", DeleteUserAPIHandler),
        (r"/api/logs", LogsAPIHandler),
        (r"/api/logs/export/csv", LogsExportHandler),
        # 页面处理器
        (r"/user_management.html", UserManagementHandler),
        (r"/initialization.html", InitializationPageHandler),
        # 文件管理API端点
        (r"/api/files/list", FileListAPIHandler),
        (r"/api/files/upload", FileUploadAPIHandler),
        (r"/api/files/download", FileDownloadAPIHandler),
        (r"/api/files/delete", FileDeleteAPIHandler),
        (r"/api/files/rename", FileRenameAPIHandler),
        # 聊天室API端点
        (r"/api/chat/send", ChatSendAPIHandler),
        (r"/api/chat/messages", ChatMessagesAPIHandler),
        (r"/api/chat/recent", ChatRecentAPIHandler),
        (r"/api/chat/online_users", ChatOnlineUsersAPIHandler),
        # WebSocket端点
        (r"/ws/chat", ChatWebSocketHandler),
        (r"/websockify", VncWebSocketProxy),
        (r"/(.*)", StaticFileHandler, {"path": NOVNC_DIR}),
    ], 
    debug=False,
    cookie_secret="webvnc-secret-key-2025",
    template_path=BASE_DIR)

def start_server(host='0.0.0.0', port=8443):
    """启动SSL服务器"""
    logger.info("=" * 60)
    logger.info("🚀 WebVNC Tornado SSL 服务器")
    logger.info("=" * 60)
    logger.info(f"🌐 服务器地址: {host}:{port}")
    logger.info(f"🎯 目标VNC: {VNC_HOST}:{VNC_PORT}")
    logger.info(f"🔗 访问地址: https://{host}:{port}/")
    logger.info(f"🔌 WebSocket地址: wss://{host}:{port}/websockify")
    logger.info(f"📁 SSL证书: {CERT_FILE}")
    logger.info("=" * 60)
    
    # 检查证书文件
    if not os.path.exists(CERT_FILE) or not os.path.exists(KEY_FILE):
        logger.error(f"❌ SSL证书文件不存在: {CERT_FILE} 或 {KEY_FILE}")
        return False
    
    try:
        # 创建应用
        app = create_app()
        
        # 创建SSL上下文
        ssl_ctx = ssl.create_default_context(ssl.Purpose.CLIENT_AUTH)
        ssl_ctx.load_cert_chain(CERT_FILE, KEY_FILE)
        logger.info("✅ SSL证书加载成功")
        
        # 创建HTTP服务器
        server = tornado.httpserver.HTTPServer(app, ssl_options=ssl_ctx)
        server.listen(port, address=host)
        
        logger.info(f"🎉 服务器启动成功！")
        logger.info(f"💡 请在浏览器中访问: https://localhost:{port}/")
        logger.info(f"⚠️  浏览器可能会提示证书不安全，这是正常的，请点击'继续访问'")
        
        # 启动事件循环
        tornado.ioloop.IOLoop.current().start()
        
    except KeyboardInterrupt:
        logger.info("\n🛑 正在关闭服务器...")
        server.stop()
        tornado.ioloop.IOLoop.current().stop()
        logger.info("✅ 服务器已关闭")
        
    except Exception as e:
        logger.error(f"❌ 服务器启动失败: {e}")
        return False
    
    return True

# ================== 主程序 ==================
if __name__ == "__main__":
    import argparse
    
    parser = argparse.ArgumentParser(description='WebVNC Tornado SSL 服务器')
    parser.add_argument('--host', default='0.0.0.0', help='监听地址 (默认: 0.0.0.0)')
    parser.add_argument('--port', type=int, default=8443, help='监听端口 (默认: 8443)')
    parser.add_argument('--vnc-host', default=VNC_HOST, help=f'VNC服务器地址 (默认: {VNC_HOST})')
    parser.add_argument('--vnc-port', type=int, default=VNC_PORT, help=f'VNC服务器端口 (默认: {VNC_PORT})')
    
    args = parser.parse_args()
    
    # 更新VNC配置
    VNC_HOST = args.vnc_host
    VNC_PORT = args.vnc_port
    
    # 启动服务器
    start_server(args.host, args.port)
